﻿package kliment.controls.mediaplayer.core.players {
	import flash.events.AsyncErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	import kliment.controls.mediaplayer.skin.ViewPort;
	import kliment.events.PlayerEvent;
	import kliment.utils.IntervalTimer;
	import kliment.utils._Sprite;

	/**
	 * ...
	 * @author	Kliment
	 * @version	0.0.5
	 * 
	 * class name: kliment.controls.mediaplayer.core.players.FLVPalyer
	 */
	public class FLVPlayer extends AbstractPlayer implements IPlayer {
		private var _netConnection:NetConnection;
		private var _netStream:NetStream;
		private var _customClient:Object;
		public var videoParameters:VideoParameters;
		private var _video:Video;
		private var _viewport:ViewPort;
		
		public function FLVPlayer() {
			
		}
		
		private function _init():void {
			_intervalTimer = new IntervalTimer(_updateInfo, UPDATE_DELAY, true, false);
			_netConnection = new NetConnection();
			_netConnection.addEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
			_netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityErrorHandler);
			_netConnection.connect(null);
		}
		
		private function _connectStream():void {
            _netStream = new NetStream(_netConnection);
			_netStream.soundTransform = soundTransform;
			_netStream.addEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
			_netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, _asyncErrorHandler);
			_netStream.client = new CustomClient(this);
			_netStream.play(_url);
			_netStream.soundTransform = soundTransform;
			
			_intervalTimer.start();
			_video = new Video();
			_video.smoothing = true;
			_video.attachNetStream(_netStream);
			if (_viewport) 
				_viewport.setVideo(_video);
			_output = _video;
        }
		
		private function _netStatusHandler(event:NetStatusEvent):void {
			//trace(event.info.code)
			switch (event.info.code) {
				case "NetConnection.Connect.Success":
					_connectStream();
				break;
				
				case "NetStream.Play.Start":
					_state = PlayerEvent.PLAYING;
					dispatchEvent(new PlayerEvent(PlayerEvent.PLAY));
				break;
				
				case "NetStream.Buffer.Empty":
					//dispatchEvent(new PlayerEvent(PlayerEvent.BUFFERING));
				break;
				
				case "NetStream.Buffer.Full":
					//_host.dispatchEvent(new UniversalPlayerEvent(UniversalPlayerEvent.BUFFER_FULL));
				break;
				
				case "NetStream.Buffer.Flush":
					
				break;
				
				case "NetStream.Seek.Notify":
					
				break;
				
				case "NetStream.Play.StreamNotFound": 
				case "NetStream.Play.Failed":
				case "NetConnection.Connect.Failed":
				case "NetConnection.Connect.Rejected":
				case "NetStream.Play.Stop":
					super.stop();
					dispatchEvent(new PlayerEvent(PlayerEvent.PLAY_COMPLETE));
				break;
			}
        }
		
		private function _updateInfo():void {
			_bytesTotlal = _netStream.bytesTotal;
			_bytesLoaded = _netStream.bytesLoaded;
			if (_bytesLoaded != _bytesTotlal )
				dispatchEvent(new PlayerEvent(PlayerEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotlal));
			
			if (_state == PlayerEvent.PLAYING) {
				dispatchEvent(new PlayerEvent(PlayerEvent.PLAYING, false, false, _bytesLoaded, _bytesTotlal,  position));
			}
		}
		
		private function _securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
        }
		
		private function _asyncErrorHandler(event:AsyncErrorEvent):void {
            // ignore AsyncErrorEvent events.
        }
		
		override public function load(url:String):void {
			remove();
			super.load(url);
			_init();
		}
		
		override public function play():void {
			if (position > .99)
				_netStream.seek(0);
			_netStream.resume();
			super.play();
		}
		
		override public function pause():void {
			_netStream.pause();
			super.pause();
		}
		
		override public function stop():void {
			_netStream.seek(0);
			_netStream.close();
			super.stop();
		}
		
		override public function forward():void {
			_netStream.seek(_netStream.time + STEP_SECONDS);
		}
		
		override public function back():void {
			_netStream.seek(_netStream.time - STEP_SECONDS * 3);
		}
		
		override public function get position():Number { return _netStream.time / duration; }
		override public function set position(value:Number):void {
			_netStream.seek(videoParameters.duration * value);
		}
		
		override public function get soundTransform():SoundTransform { return super.soundTransform; }
		override public function set soundTransform(value:SoundTransform):void {
			super.soundTransform = value;
			_netStream.soundTransform = soundTransform;
		}
		
		override public function get duration():Number { 
			if (videoParameters)
				return videoParameters.duration; 
			return super.duration;
		}
		
		public function get viewport():ViewPort { return _viewport; }
		public function set viewport(value:ViewPort):void {
			_viewport = value;
		}
		
		public function onMetaData():void {
			_video.width = videoParameters.width;
			_video.height = videoParameters.height;
			if (_viewport)
				_viewport.update();
		}
		
		override public function remove():void {
			if (_netStream) {
				_netStream.close();
				_netStream.removeEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
				_netStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, _asyncErrorHandler);
			}
			if (_netConnection) {
				_netConnection.removeEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
				_netConnection.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityErrorHandler);
				_netConnection.connect(null);
			}
			_Sprite.remove(_video);
			super.remove();
		}
	}

}

import kliment.controls.mediaplayer.core.players.FLVPlayer
class CustomClient {
	private var _host:FLVPlayer;
	
	public function CustomClient(host:FLVPlayer):void {
		_host = host;
	}
	
    public function onMetaData(info:Object):void {
        _host.videoParameters = new VideoParameters(info.duration, info.width, info.height, info.framerate);
		_host.onMetaData();
    }
	
    public function onCuePoint(info:Object):void {
        trace("cuepoint: time=" + info.time + " name=" + info.name + " type=" + info.type);
    }
	
	public function onXMPData(info:Object):void {  }
}

class VideoParameters {
	public var duration:Number;
	public var width:Number;
	public var height:Number;
	public var framerate:Number;
	
	public function VideoParameters(duration:Number = 0, width:Number = 0, height:Number = 0,  framerate:Number = 0):void {
		this.duration = duration;
		this.width = width;
		this.height = height;
		this.framerate = framerate;
	}
	
	public function toString():String {
		return "VideoParameters: duration=" + duration + " width=" + width + " height=" + height + " framerate=" + framerate;
	}
}